package com.base.animation

import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LifecycleRegistry
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.PorterDuff
import android.util.AttributeSet
import android.util.Log
import android.view.View
import com.base.animation.helper.PathObjectDeal
import com.base.animation.model.AnimPathObject
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.channels.ticker
import kotlinx.coroutines.launch
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.supervisorScope

/**
 * @author:zhouzechao
 * @date: 1/8/21
 * description：
 */
private const val TAG = "AnimView"

@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class AnimView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr), LifecycleOwner, IAnimView {
    private var mLifecycleRegistry = LifecycleRegistry(this)

    private var loggingExceptionHandler = CoroutineExceptionHandler { context, throwable ->
        Log.e("CoroutineException", "Coroutine exception occurred. $context", throwable)
    }

    private val animScope =
        CoroutineScope(SupervisorJob() + newFixedThreadPoolContext(1, "anim") +
            loggingExceptionHandler)

    private var tickerChannel: ReceiveChannel<Unit>? = null

    /**
     * pathObject转化
     */
    private var interval = 1000L / 60
    private val pathObjectDeal = PathObjectDeal().apply {
        intervalDeal = interval
    }

    override fun setFPS(fps: Int) {
        interval = 1000L / fps
        pathObjectDeal.intervalDeal = interval
    }

    override fun setCacheTime(cacheTime: Long) {
        pathObjectDeal.cacheTime = cacheTime
    }

    override fun resume() {
        if (tickerChannel == null) {
            tickerChannel = ticker(delayMillis = interval, initialDelayMillis = 0)
            animScope.launch {
                Log.d(TAG, "lockCanvas ---- ${Thread.currentThread().name}-------start")
                supervisorScope {
                    tickerChannel?.consumeEach {
                        postInvalidate()
                        pathObjectDeal.runCacheStrategy()
                    }
                }
            }
        }
    }

    override fun pause() {
        tickerChannel?.cancel()
        tickerChannel = null
    }

    override fun draw(canvas: Canvas?) {
        super.draw(canvas)
        canvas?.let {
            pathObjectDeal.animDrawObjects.forEach {
                it.draw(canvas, pathObjectDeal)
            }
        }
    }

    /**
     * 结束动画
     */
    override fun endAnimation() {
        pause()
        pathObjectDeal.release()
    }

    /**
     * 添加动画播放
     * @param display
     */
    override fun addAnimDisplay(animPathObject: AnimPathObject) {
        pathObjectDeal.sendAnimPath(animPathObject)
    }

    /**
     *
     */
    override fun getLifecycle(): Lifecycle {
        return mLifecycleRegistry
    }
}